#include <bits/types/sigset_t.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

// 定义一个实时信号
#define SIG_ME (SIGRTMIN+6)

// 向当前进程发送实时信号，实时信号会有一个范围，40 就表示SIGRTMIN+6，kill -40 pid

// 定义接收信号的函数指针, 实时信号不会丢失数据
static void int_handler(int s)
{
	write(1,"!",1);
}
/*
 * 信号集，对一组信号的阻塞和放开，与信号的恢复
 * sigprocmask(参数1，参数2，参数3)
 * 参数1：	SIG_BLOCK		阻塞信号
 * 			SIG_UNBLOCK		放开信号
 * 			SIG_SETMASK		恢复信号
 * 参数2：信号集
 * 参数3：信号集
 * */
int main()
{

	int i;

	// 注册一个处理SIGINT信号的方式，SIG_IGN表示忽略该信号, 当按住Ctrl + c 的时候终止信号被忽略
	//signal(SIGINT,SIG_IGN);
	// 当收到SIGINT信号，会触发int_handler指针函数
	signal(SIG_ME,int_handler);
	sigset_t set, oset, sset;
	
	sigemptyset(&set); 			// 清空信号集
	sigaddset(&set, SIG_ME);	// 添加信号
	// 在编写程序的时候需要，需要考虑自己所处于一个模块之中，要考虑当前信号集的状态，在进入和出去，需要保证信号集的状态不变，需要使用sset保存信号集的状态
	// 一般先让信号集处于UNBLOCK状态，并且保存之前的状态到sset
	sigprocmask(SIG_UNBLOCK, &set, &sset);
	
	// 进入前，先阻塞信号集
	sigprocmask(SIG_BLOCK, &set, &oset);
	for (i = 0; i < 10; i++) {

		for (i = 0; i < 5; i++) {
			write(1,"*",1);
			sleep(1);
		}
		write(1,"\n",1);
		// 类似pause，等待一个信号，但是suspend会将信号状态恢复到oset，并且是原子操作，收到信号后，程序继续执行
		sigsuspend(&oset);
#if 0
		// 模拟sigsuspend，但是下面代码不是原子操作，会导致bug
		sigset_t tmpset;
		sigprocmask(SIG_SETMASK, &oset, &tmpset); 	// 恢复BLOCK之前的状态，并记住现在的状态
		pause();
		sigprocmask(SIG_SETMASK, &tmpset, NULL); 	// 恢复到pause之前的状态
#endif
	}

	// 功能执行完毕需要使用SIG_SETMASK恢复到之前的信号集状态
	sigprocmask(SIG_SETMASK, &sset, NULL);

	exit(0);
}
